﻿using System;
using System.Collections.Generic;
using System.Linq;
using ITSP.SharePoint.CacheRefresh.Adapters;
using ITSP.SharePoint.CacheRefresh.Common;
using ITSP.SharePoint.CacheRefresh.Entities;
using ITSP.SharePoint.CacheRefresh.Interfaces;
using ITSP.SharePoint.CacheRefresh.SpecialCases;
using Microsoft.Practices.SharePoint.Common.Logging;
using Microsoft.Practices.SharePoint.Common.ServiceLocation;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace ITSP.SharePoint.CacheRefresh.Repositories
{
   

    /// <summary>
    /// Allows the manupulation of the cache configuration list.
    /// </summary>
    public class SPCacheConfigurationRepository : ICacheConfigurationRepository
    {
        private ILogger _logger = SharePointServiceLocator.GetCurrent().GetInstance<ILogger>();
        private SPSite _site;
        private SPWeb _web;
        private SPList _list;

        /// <summary>
        /// Default Constructor
        /// </summary>
        public SPCacheConfigurationRepository()
        {
            
        }

        /// <summary>
        /// Enable the Configuration Repository with a host Web Application url.
        /// The class is expecting a Url which points to the root site of the Web Application. (http://sharepoint)
        /// </summary>
        public SPCacheConfigurationRepository(string hostSiteUrl)
        {
            _site = new SPSite(hostSiteUrl);
            _site.CatchAccessDeniedException = false;

            _web = _site.RootWeb;
            _list = _web.Lists.TryGetList(Constants.Lists.CacheList);
            if(_list==null)
            {
                throw new SPException(String.Format("Cannot find Cache Configuration List {0}", Constants.Lists.CacheList));
            }
        }

        /// <summary>
        /// Get the Instance of the SharePoint Cache Configuration Repository.
        /// </summary>
        /// <returns></returns>
        public static SPCacheConfigurationRepository GetInstance(SPSite site)
        {
            SPCacheConfigurationRepository repository = new SPCacheConfigurationRepository(site.Url);
            return repository;
        }

        /// <summary>
        /// Get List of all the Cache Configuration Items
        /// </summary>
        /// <returns></returns>
        public IList<ICacheConfigItem> GetAll()
        {
            IList<SPCacheConfigItem> listOfItems=new List<SPCacheConfigItem>();
                
            SPListItemCollection itemCollection = _list.Items;
            foreach (SPListItem item in itemCollection)
            {
                SPCacheConfigItem configItem = SPListItemToSPCacheConfigItem.Convert(item) as SPCacheConfigItem;
                listOfItems.Add(configItem);
            }

            return listOfItems.OfType<ICacheConfigItem>().ToList();
        }

        /// <summary>
        /// Gets a Cache Configuration Item
        /// </summary>
        /// <returns></returns>
        public ICacheConfigItem Get(string cacheKey)
        {
            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::Get(Cache Key: {0}) Enter", cacheKey), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            ICacheConfigItem item = null;

            IList<ICacheConfigItem> listOfItems = GetAll();
            item = listOfItems.FirstOrDefault(c => c.CacheKey.Equals(cacheKey, StringComparison.InvariantCultureIgnoreCase));
            if(item==null)
            {
                item=new SPCacheConfigItemNotFound();
            }

            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::Get(Found Cache key: {0}) Exit", item.Exists), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            return item;
        }

        /// <summary>
        /// Get the SharePoint List Item associated to the Cache Configuration Item
        /// </summary>
        /// <param name="cacheKey">The Cache Key to search against</param>
        /// <returns>The associated SharePoint List Item</returns>
        public SPListItem GetListItem(string cacheKey)
        {
            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::GetListItem(Cache Key: {0}) Enter", cacheKey), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            SPListItem listItem = null;
            ICacheConfigItem item = null;

            item = Get(cacheKey);
            if (item.Exists)
            {
                listItem = _list.Items.GetItemById(item.ListItemId);
            }

            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::GetListItem() Exit"), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            return listItem;
        }

        /// <summary>
        /// Adds a Cache Configuration Item to the Cache Configuration List.
        /// </summary>
        /// <param name="cacheKey">Cache Key</param>
        /// <param name="description">Description of the Cache Item</param>
        /// <param name="cacheDependencyLocation">Path to the file that is used as the cache dependency target.</param>
        /// <param name="cacheFrequency">The number of minutes between when the cache refresh occurs</param>
        /// <param name="cacheEnabled">Is the Cache enabled?</param>
        /// <returns></returns>
        public ICacheConfigItem Add(string cacheKey, string description, string cacheDependencyLocation, int cacheFrequency, bool cacheEnabled)
        {
            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::Add(Cache Key: {0}) Enter", cacheKey), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            ICacheConfigItem item = null;

            try
            {
                ICacheConfigItem checkConfig = Get(cacheKey);
                if(checkConfig.Exists)
                {
                    throw new ArgumentException(String.Format("Cache Config Item with Key:{0} Already exists.", cacheKey));
                }

                SPListItem listItem = _list.Items.Add();
                listItem[Constants.Fields.Title] = cacheKey;
                listItem[Constants.Fields.CacheDescription] = description;
                listItem[Constants.Fields.CacheFileDependencyPath] = cacheDependencyLocation;
                listItem[Constants.Fields.CacheFrequency] = cacheFrequency;
                listItem[Constants.Fields.CacheEnabled] = cacheEnabled;
                listItem.Update();

                item = SPListItemToSPCacheConfigItem.Convert(listItem) as ICacheConfigItem;
                
            }
            catch (Exception)
            {

                throw;
            }
            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::Add() Exit", cacheKey), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            return item;
        }

        /// <summary>
        /// Deletes a Cache Configuration Item
        /// </summary>
        /// <returns></returns>
        public bool Delete(string cacheKey)
        {
            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::Delete(Cache Key: {0}) Enter", cacheKey), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            bool bSuccess = false;
            
            try
            {
                ICacheConfigItem checkConfig = Get(cacheKey);
                if (!checkConfig.Exists)
                {
                    throw new ArgumentException(String.Format("Cache Config Item with Key:{0} does not exist.", cacheKey));
                }

                SPListItem listItem = _list.Items.GetItemById(checkConfig.ListItemId);
                listItem.Delete();
                bSuccess = true;
                
            }
            catch (Exception)
            {
                
                throw;
            }

            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::Delete(Success: {0}) Enter", bSuccess), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            return bSuccess;
        }

        /// <summary>
        /// Updates SharePoint with the Cache Configuration Item information.
        /// </summary>
        /// <returns></returns>
        public ICacheConfigItem Update(ICacheConfigItem configItem)
        {
            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::Update(Cache Key: {0}) Enter", configItem.CacheKey), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            ICacheConfigItem updatedItem = null;
            if(configItem.ListItemId<=0)
            {
                throw new ArgumentException("SPCacheConfigItem is missing a List Item Id, ensure the object is added to SharePoint List before updating.");
            }

            SPListItem listItem = _list.Items.GetItemById(configItem.ListItemId);
            listItem[Constants.Fields.Title] = configItem.CacheKey;
            listItem[Constants.Fields.CacheDescription] = configItem.Description;
            listItem[Constants.Fields.CacheFileDependencyPath] = configItem.CacheDependencyPath;
            listItem[Constants.Fields.CacheFrequency] = configItem.CacheFrequency;
            listItem[Constants.Fields.CacheEnabled] = configItem.CacheEnabled;
            listItem.Update();

            updatedItem = SPListItemToSPCacheConfigItem.Convert(listItem) as ICacheConfigItem;

            _logger.TraceToDeveloper(String.Format("SPCacheConfigurationRepository::Update() Exit"), 0, TraceSeverity.Verbose, Constants.Logging.DefaultLoggingCategory);
            return updatedItem;
        }

        /// <summary>
        /// Dispose of any objects used.
        /// </summary>
        public void Dispose()
        {
            if(_list!=null)
            {
                _list = null;
            }
            if(_web!=null)
            {
                _web.Dispose();
            }
            if (_site != null)
            {
                _site.CatchAccessDeniedException = true;
                _site.Dispose();
            }
        }
    }
}
